/*
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.merak.core.web.mvc;

import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.merak.core.web.HttpRequest;
import org.merak.core.web.HttpResponse;
import org.merak.core.web.mvc.annotation.NotNull;
import org.merak.core.web.mvc.annotation.NotOutOfBound;
import org.merak.core.web.mvc.validation.BatchValidator;
import org.merak.core.web.mvc.validation.NotNullValidator;
import org.merak.core.web.mvc.validation.NotOutOfBoundValidator;

public class PageController {

    //~ Attributes ///////////////////////////////////////////////////////////////
	//****************************************************************************
	private String               businessName  = null;
	private Class<?>             businessClass = null;
	private List<BatchValidator> validatorList = new LinkedList<BatchValidator>();

	//~ Constructors /////////////////////////////////////////////////////////////
	//****************************************************************************
	public PageController(String businessName,Class<?> businessClass)
		throws Exception
	{

   		// Find the class that corresponds to the business
   		this.businessName  = businessName;
   		this.businessClass = businessClass;

   		// Compile annotations of execute(HttpWebRequest,HttpWebResponse)
   		this.compileAnnotations();

	}

    //~ Methods //////////////////////////////////////////////////////////////////
	//****************************************************************************
    private void compileAnnotations()
    	throws SecurityException, NoSuchMethodException
    {
		/* Now, process annotations of method execute(HttpRequest,HttpResponse)
		 * define in the IBusinessLogic interface */
		Method method = this.businessClass.getMethod(
   			"execute",HttpRequest.class,HttpResponse.class
   		);

		// Look up for NotNull annotation
		NotNull notNull = method.getAnnotation(NotNull.class);
		if (notNull != null) this.validatorList.add(
			new NotNullValidator(notNull)
		);

		// Look up for NotOutOfBound annotation
		NotOutOfBound notOutOfBound = method.getAnnotation(NotOutOfBound.class);
		if (notOutOfBound != null) this.validatorList.add(
			new NotOutOfBoundValidator(notOutOfBound)
		);

    }
	//****************************************************************************
    /** Find the object responsible for handling the specific requested business.
     *  @param businessName the key-name of the requested business object.
     *  @return one business object from the specified businessPackage
     *  @throws ServletException */
    private IBusinessLogic getBusinessLogic() throws ServletException {

    	try {
    		return (IBusinessLogic) this.businessClass.newInstance();
    	}
    	catch (Exception e) { throw new ServletException(
   			"The Bussiness Logic cannot be started: " + this.businessName,e
   		);}

    }
    //****************************************************************************
    public String runBusinessLogic(HttpServletRequest req, HttpServletResponse res)
    	throws ServletException, ExceptionView, SecurityException
    {
		// Authorize (or not) current user
    	IBusinessLogic business = this.getBusinessLogic();
		if ( !business.authorize(req.getSession()) ) throw new SecurityException(
			"The Business Logic Execution is not authorized for this user"
		);

    	try {
    		// Prepare Wrapped Request and Response
    		HttpRequest  request  = new HttpRequest(req);
    		HttpResponse response = new HttpResponse(res);
    		// Run validations, blocking execution if necessary
    		for (BatchValidator v : this.validatorList) {
    			if ( !v.validate(request,response) ) return v.getView();
    		}
    		// It is all right, the business can execute
    		return business.execute(request,response);
    	}
    	catch (ExceptionView view) {
       		throw view;
    	}
    	catch (Throwable e) { throw new ServletException(
    		"The Business Logic Execution caused an Error: " + this.businessName,e
    	);}

    }
    //****************************************************************************
    public String runExceptionLogic(HttpServletRequest req, HttpServletResponse res)
    	throws ServletException
    {
    	/* All users must have privileges to execute exception logics,
    	 * even if otherwise stated by 'authorize' method. */
    	try {
    		// Prepare Wrapped Request and Response
    		HttpRequest  request  = new HttpRequest(req);
    		HttpResponse response = new HttpResponse(res);
    		// Run validations, blocking execution if necessary
    		for (BatchValidator v : this.validatorList) {
    			if ( !v.validate(request,response) ) return v.getView();
    		}
    		// It is all right, the business can execute
    		return this.getBusinessLogic().execute(request,response);
    	}
    	catch (Throwable e) { throw new ServletException(
    		"The Exception Logic Execution caused an Error: " + this.businessName,e
    	);}

    }
    //****************************************************************************

}
